use std::time::Duration;

use base_data::channel::{
	event::ChannelEvent, Channel, ChannelCallDirection, ChannelState, CommandMsg, EndReason,
};
use tokio::sync::mpsc::error::TryRecvError;
use tools::{
	error::Error,
	global_defin::tokio_runtime::get_rt,
	utils::{gen_id::get_now_duration, sugre::exec_no_result_error_log},
	ResultEx, ResultNull,
};
use tracing::{debug, error, info, span, Instrument, Level};

use crate::{
	business::{
		bus_trait::Business,
		extra::{has_extra, Extra},
		inbound400::logic::{
			dial_test::DialTestIn, no_allow_caller::NoAllowCaller, no_money::NoMoney,
			node_time_refuse::NodeTimeRefuse, pause::Pause,
		},
		RunContext, TurnNumInfo, TurnnumCallType,
	},
	config::business_config,
	db::persistence::InboundDBO,
	link_to_sip::kill_channel,
	CallingLogType,
};

use super::{
	context::{BusinessState, InboundRunContext},
	logic::{invalid_target::InvalidTarget, ivr::IVR, sequence::Sequence, sip_transfer::SipTransfer},
};

///启动一个呼入的相关业务处理
#[inline(always)]
pub(crate) fn run_call_in(channel: Channel) {
	let span = span!(Level::ERROR, "", bus_id = channel.id);
	get_rt().spawn(start_run_call_in_business(channel).instrument(span));
}

pub(crate) async fn start_run_call_in_business(channel: Channel) {
	debug!("启动呼入业务处理:{}", channel);
	let mut context = match InboundRunContext::new(channel).await {
		Ok(ct) => ct,
		Err((ch, e)) => {
			match e {
				//目前未找到异常是需要返回不一样的内容
				Error::NotFound(_) => {
					info!("未找到目的码 :{}..退出", ch.dest_num);
					exec_no_result_error_log("关闭呼入通道失败", || {
						ch.send(CommandMsg::HangupChannel(ch.id, EndReason::NoCalledNum))
					});
				}
				//出现其他错误,退出当前协程,并发送关闭命令
				_ => {
					info!("启动呼入业务失败..退出");
					exec_no_result_error_log("关闭呼入通道失败", || {
						ch.send(CommandMsg::KillChannel(ch.id))
					});
				}
			}

			// tokio::time::sleep(Duration::from_secs(2)).await;
			return;
		}
	};

	let mut handler = create_business_handle(&mut context).await;
	let mut check_time = get_now_duration() + Duration::from_millis(200);

	if let Err(e) = handler.start_call(&mut context).await {
		error!("启动处理失败:{}", e);
		context.business_state = BusinessState::End(EndReason::ServerInternalError);
	}

	loop {
		if let BusinessState::End(_) = context.business_state {
			break;
		}

		//处理a腿事件
		loop {
			match context.caller_channel_mut().try_recv() {
				//没有得到事件.跳过
				Err(TryRecvError::Empty) => break,
				Ok(ev) => match execute(handler, &mut context, ev).await {
					//正常不用处理
					Ok(_) => {}
					//有替换处理节点.换节点以后执行一次开始操作
					Err(Error::ReplaceNode) => {
						handler = match context.take_next_handler() {
							Some(h) => h,
							None => {
								error!("没有设置下一个处理流程");
								context.business_state = BusinessState::End(EndReason::ServerInternalError);
								break;
							}
						};

						if let Err(e) = handler.start_call(&mut context).await {
							error!("处理失败:{}", e);
							context.business_state = BusinessState::End(EndReason::ServerInternalError);
						}
					}
					Err(e) => {
						error!("处理呼入事件失败:{}", e);
						context.business_state = BusinessState::End(EndReason::ServerInternalError);
						break;
					}
				},
				Err(TryRecvError::Disconnected) => {
					context.business_state = BusinessState::End(EndReason::CallerPending);
					break;
				}
			}
		}

		loop {
			match context.called_channel_try_recv() {
				//没有得到事件.跳过
				Err(TryRecvError::Empty) => break,
				Ok(ev) => {
					match execute(handler, &mut context, ev).await {
						//正常不用处理
						Ok(_) => {}
						//有替换处理节点.换节点以后执行一次开始操作
						Err(Error::ReplaceNode) => {
							handler = match context.take_next_handler() {
								Some(h) => h,
								None => {
									error!("没有设置下一个处理流程");
									context.business_state = BusinessState::End(EndReason::ServerInternalError);
									break;
								}
							};

							if let Err(e) = handler.start_call(&mut context).await {
								error!("处理失败:{}", e);
								context.business_state = BusinessState::End(EndReason::ServerInternalError);
							}
						}
						Err(e) => {
							error!("处理呼入事件失败:{}", e);
							context.business_state = BusinessState::End(EndReason::ServerInternalError);
							break;
						}
					}
				}
				Err(TryRecvError::Disconnected) => {
					context.business_state = BusinessState::End(EndReason::CallerPending);
					break;
				}
			}
		}

		//每200ms进行一次检查,这个不影响执行.
		if get_now_duration() >= check_time {
			check_time += Duration::from_millis(200);
			if let Err(e) = handler.check(&mut context).await {
				error!("检查失败:{}", e);
				break;
			}
		}

		//20ms进行一次处理
		tokio::time::sleep(Duration::from_millis(20)).await;
	}

	info!("呼入业务处理结束..context:{context:?}");
	//结束的处理
	if let Err(e) = kill_channel(context.caller_channel(), EndReason::InitiativeHangup) {
		error!("关闭呼入通道失败:{}", e);
	}

	if let Some(o_ch) = context.called_channel() {
		if let Err(e) = kill_channel(o_ch, EndReason::InitiativeHangup) {
			error!("关闭呼出通道失败:{}", e);
		}
	}
}

async fn execute(
	headler: &'static dyn Business<C = InboundRunContext>,
	ct: &mut InboundRunContext,
	event: ChannelEvent,
) -> ResultNull {
	debug!("处理收到的事件:{:?}", event);
	match event {
		ChannelEvent::ChannelCallState(id, state) => headler.change_call_state(ct, id, state).await?,
		ChannelEvent::ChannelAnswer(id) => headler.answer(ct, id).await?,
		ChannelEvent::DTMF(id, dtmf) => headler.get_dtmf(ct, id, dtmf).await?,
		ChannelEvent::PlaybackStop(id) => headler.play_back_stop(ct, id).await?,
		ChannelEvent::ChannelBridge => headler.bridge(ct).await?,
		ChannelEvent::ChannelHangup(id, reason) => headler.hangup(ct, id, reason).await?,
		ChannelEvent::ChannelOriginate(ch) => {
			debug!("创建b_leg通道:{}", ch.id);
			ct.called_channel_set(Channel {
				id: ch.id,
				state: ChannelState::CallOut,
				direction: ChannelCallDirection::OutBound,
				caller_num: String::default(),
				dest_num: ct.turn_num.num.clone(),
				to_switch: ch.to_switch,
				from_switch: ch.from_switch,
			});
		}
		ChannelEvent::OriginateError(reason) => headler.hangup(ct, ct.called_id(), reason).await?,
		ChannelEvent::UserRegist | ChannelEvent::Unknow | ChannelEvent::ChannelUnbridge => {
			error!("还未处理的事件:{:?}", event)
		}
	}

	Ok(())
}

async fn create_business_handle(
	ct: &mut InboundRunContext,
) -> &'static dyn Business<C = InboundRunContext> {
	if ct.caller_num().is_empty() || ct.target().is_empty() || ct.is_empty() {
		return &InvalidTarget;
	}

	match pre_call_judgment(ct).await {
		//这是存在呼叫限制..直接进入指定的处理节
		Ok(Some((h, r))) => {
			let _ = InboundDBO::record_calling_log(
				&ct,
				CallingLogType::GiveACall,
				r,
				None,
				Some(ct.node_info.node_id),
				&ct.call_start_time,
				TurnnumCallType::Unknow,
			)
			.await;

			h
		}
		//这里其实是正常..进入
		Ok(None) => match (has_extra(ct.flag, Extra::ToSipTran), ct.node_info.flag) {
			//根据情况判断是否使用sip中继功能，中继功能有可能呼转中继和sip中继。需要自己判断
			(true, _) => {
				//如果存在sip中继的配置，跳转至sip的操作。
				match InboundDBO::get_sip_transfer_info(ct.target()).await {
					Ok((url, phone_num)) => {
						ct.turn_num = TurnNumInfo::new(
							phone_num,
							60,
							ct.node_info.node_id,
							TurnnumCallType::CallTerminal,
						);
						ct.sip_tran_info = url.parse().ok();
						&SipTransfer
					}
					Err(e) => {
						error!("设置了中继,但未设置中继对应的sip消息.e:{:?}", e);
						&InvalidTarget
					}
				}
			}
			(false, 1) => &IVR,
			(false, 2) => &Sequence,
			_ => &InvalidTarget,
		},
		Err(e) => {
			error!("呼叫前判断失败:{}", e);
			exec_no_result_error_log("关闭呼入通道失败", || {
				ct.caller_channel()
					.send(CommandMsg::KillChannel(ct.caller_channel().id))
			});

			&InvalidTarget
		}
	}
}

///呼叫开始前的判断，这里根据不同的逻辑处理相关不呼叫内容
/// 返回值为修改后的节点类型和结束原因。这是呼叫前判断出来各种情况的处理入口。根据需要有可能修改放音彩铃等内容。
/// 正常呼叫返回None
#[inline]
async fn pre_call_judgment(
	context: &mut InboundRunContext,
) -> ResultEx<Option<(&'static dyn Business<C = InboundRunContext>, EndReason)>> {
	//此来电是一个拨测来电
	if InboundDBO::is_dial_test_caller(&context.caller_num()).await? {
		info!("当前是拨测来电");

		return Ok(Some((&DialTestIn, EndReason::DialTest)));
	}

	//用户金额不足.这个所有业务都一样进行操作
	if context.money < context.talk_rate() {
		info!("当前用户金额不够.");
		return Ok(Some((&NoMoney, EndReason::NotEnoughMoney)));
	}

	//当前主节点被时段拒接，
	if context.node_info.flag == -1 {
		info!("用户设置了时段拒接");
		return Ok(Some((&NodeTimeRefuse, EndReason::NoAllowTimeCaller)));
	}

	//用户被暂停
	if has_extra(context.flag, Extra::Pause) {
		info!("当前用户已经被暂停.");
		return Ok(Some((&Pause, EndReason::PhonePause)));
	}

	match InboundDBO::allow_callin(context.caller_num(), context.target()).await? {
		1 => Ok(None),
		//白名单限制被拒接
		120 => {
			info!("白名单限制被拒接.");
			business_config()
				.caller_not_in_white_list
				.clone_into(&mut context.node_info.conn_begin_bell_path);

			Ok(Some((&NoAllowCaller, EndReason::NoInWhiteListCaller)))
		}
		//黑名单限制被拒接
		121 => {
			info!("黑名单限制被拒接.");
			business_config()
				.caller_in_black_list
				.clone_into(&mut context.node_info.conn_begin_bell_path);
			Ok(Some((&NoAllowCaller, EndReason::InBlackListCaller)))
		}
		//区域限制被拒接
		123 => {
			info!("区域限制被拒接.");
			business_config()
				.area_refuse
				.clone_into(&mut context.node_info.conn_begin_bell_path);
			Ok(Some((&NoAllowCaller, EndReason::NoAllowRegionCaller)))
		}
		_ => Ok(None),
		// _ => Ok((node_info.node_type, EndReason::TalkNocallerd)),
	}
}
